package com.second.app.thread.线程基础.day09.reentrantlock关键字;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author GYZ
 * @Date 2023/12/7
 * <pre>
 *   案例1：
 *        简单演示reentrantLock的使用。
 *   案例2：
 *        结合condition，来实现线程等待。
 *        线程A持有lock对象，并创建一个条件condition，在这个条件下，执行await方法，线程进入等待
 *        释放锁，主线程休眠3s，持有lock对象，执行signal唤起，此时线程A被唤醒，打印B。
 *   案例3：
 *        线程A B 共用一个condition 分别让各自线程等待  主线程 负责唤起 发现A B两线程 都醒了
 *        那么如果想单独唤醒某个线程，怎么实现？参考案例4
 *   案例4：
 *      每个线程绑定一个condition,这样唤醒的时候，就可以达到只唤醒部分线程的效果。
 *
 *   案例5：
 *       实现生产者/消费者模式，一对一交替打印
 *   案例6
 *     公平锁 fair==true，根据输出结果：线程获取锁得顺序 和线程执行得 顺序 是一致的
 *     ★ 线程Thread-1运行了
 *     ★ 线程Thread-7运行了
 *     ★ 线程Thread-6运行了
 *     ★ 线程Thread-0运行了
 *     ★ 线程Thread-5运行了
 *     ★ 线程Thread-9运行了
 *     ★ 线程Thread-4运行了
 *     ★ 线程Thread-3运行了
 *     ★ 线程Thread-8运行了
 *     ★ 线程Thread-2运行了
 *      ThreadName=Thread-1获得锁定
 *      ThreadName=Thread-7获得锁定
 *      ThreadName=Thread-6获得锁定
 *      ThreadName=Thread-0获得锁定
 *      ThreadName=Thread-5获得锁定
 *      ThreadName=Thread-9获得锁定
 *      ThreadName=Thread-4获得锁定
 *      ThreadName=Thread-3获得锁定
 *      ThreadName=Thread-8获得锁定
 *      ThreadName=Thread-2获得锁定
 *   案例7
 *     getHoldCount()：
 *                   查询当前线程保持此锁定的个数，也就是调用lock()方法的次数
 *   案例8
 *     getQueueLength()：
 *                       返回正等待获取此锁定的线程估计数，比如有5个线程，1个线程首先执行await方法，
 *                       那么调用getQueueLength()方法后返回值是4，说明有4个线程同时等待lock的释放。
 *   案例9
 *     getWaitQueueLength(Condition condition):
 *                  返回等待与此锁相关的给定条件Condition的线程估计数，比如有5个线程，每个线程都执行同一个condition对象的await方法
 *                  则调用getWaitQueueLength(Condition condition)返回5
 *
 *   案例10
 *      hasQueuedThread()
 *                       作用是查询指定的线程是否正在等待获取此锁定
 *      hasQueuedThreads()
 *                      作用是查询是否有线程是否正在等待获取此锁定
 *   案例11
 *
 *      hasWaiters(Condition condition)查询是否有线程正在等待和此锁相关的condition条件
 *      比如10个线程都进入等待状态，这时候在尝试唤醒前，获取getWaitQueueLength等待newCondition线程数.
 *
 *   案例12
 *       isHeldByCurrentThread()查询当前线程是否保持此锁定。
 *       isLocked() 查询此锁定是否由任意线程保持
 *
 *   案例13
 *       lockInterruptibly(): 如果当前线程未被中断，则获取锁定，如果已经被中断则出现异常。
 *   案例14
 *       tryLock()：仅在调用时锁定未被另一个线程保持的情况下，才获取该锁定。
 *   案例15
 *       tryLock(long timeOut,TimeUnit unit)
 *       这里演示出一个问题：线程A尝试3s内，拿到锁后，休眠10s，此时线程B并没有拿到锁，所以最终执行finally代码
 *       解锁，此时线程B解锁，但是发现此时线程锁属于A对象持有，就出现解锁和关锁不是同一个对象的问题。
 *       所以加上isHeldByCurrentThread判断锁是否由当前线程持有。
 *   案例16
 *      awaitUninterruptibly()
 *      await :线程在调用condition.await方法后处于await状态，此时调用interrupt会报错
 *             但是在调用condition.awaitUninterruptibly()后，调用thread.interrupt则不会报错。
 *   案例17
 *      awaitUtil(): n 秒 后自己唤醒自己
 *   案例18
 *      awaitUtil(): n 秒 后别人唤醒自己 线程A等待10S后，线程B执行，唤醒，但是线程A不用等待10s,既可以直接被醒
 *
 *   案例19
 *       结合condition实现交替打印
 * </pre>
 */
//案例19

class AlternatePrinter {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition conditionA = lock.newCondition();

    private final Condition conditionB = lock.newCondition();

    private boolean isPrint = true;

    public void print(String message) throws InterruptedException {
        lock.lock();
        try {
            while (isPrint) {
                conditionB.await();
            }
            System.out.println(message);
            isPrint = true;
            conditionA.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void print2(String message) throws InterruptedException {
        lock.lock();
        try {
            while (!isPrint) {
                conditionA.await();
            }
            System.out.println(message);
            isPrint = false;
            conditionB.signalAll();
        } finally {
            lock.unlock();
        }
    }

}

class Service18 {
    public static void main(String[] args) {
        AlternatePrinter alternatePrinter = new AlternatePrinter();
        new Thread(() -> {
            for (int i=0;i<10;i++){
                try {
                    alternatePrinter.print("Thread 1: "+i );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(() -> {
            for (int i=0;i<10;i++){
                try {
                    alternatePrinter.print2("Thread 2: "+i );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

//案例18
class Service17 {

    public ReentrantLock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("wait begin timer=" + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait end timer=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("notify begin timer=" + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("notify end timer=" + System.currentTimeMillis());
        } finally {
            lock.unlock();
        }
    }
}

class Run17 {
    public static void main(String[] args) throws InterruptedException {

        Service17 service17 = new Service17();
        new Thread(new Runnable() {
            @Override
            public void run() {
                service17.waitMethod();
            }
        }).start();

        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                service17.notifyMethod();
            }
        }).start();
    }
}

//案例17
class Service16 {

    public ReentrantLock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("wait begin timer=" + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait end timer=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("wait begin timer=" + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("wait end timer=" + System.currentTimeMillis());
        } finally {
            lock.unlock();
        }
    }
}

class Run16 {
    public static void main(String[] args) {

        Service16 service16 = new Service16();
        new Thread(new Runnable() {
            @Override
            public void run() {
                service16.waitMethod();
            }
        }).start();
    }
}


//案例16
class Service15 {

    public ReentrantLock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out.println("wait begin");
            condition.awaitUninterruptibly();
        } finally {
            lock.unlock();
        }
    }
}

class Run15 {
    public static void main(String[] args) {

        Service15 service15 = new Service15();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service15.waitMethod();
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();

        thread.interrupt();

    }
}


//案例15
class Service14 {
    public ReentrantLock lock = new ReentrantLock();

    public void waitMethod() {
        try {
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                System.out.println("   " + Thread.currentThread().getName() + "获得锁的时间：" + LocalDateTime.now());
                //休眠10s
                Thread.sleep(10000);
            } else {
                System.out.println("   " + Thread.currentThread().getName() + "没有获得锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                System.out.println("   " + Thread.currentThread().getName() + "解锁时间：" + LocalDateTime.now());
            }
        }
    }
}

class Run14 {
    public static void main(String[] args) {
        Service14 service14 = new Service14();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service14.waitMethod();
            }
        };

        Thread threadA = new Thread(runnable);


        Thread threadB = new Thread(runnable);

        threadA.start();

        threadB.start();
    }
}


//案例14
class Service13 {

    public ReentrantLock lock = new ReentrantLock();

    public void waitMethod() {
        if (lock.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "获得锁");
        } else {
            System.out.println(Thread.currentThread().getName() + "没有获得锁");
        }
    }
}

class Run13 {
    public static void main(String[] args) {
        Service13 service13 = new Service13();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service13.waitMethod();
            }
        };

        Thread a = new Thread(runnable);
        a.setName("A");
        a.start();

        Thread b = new Thread(runnable);
        b.setName("B");
        b.start();
    }
}

//案例13
class Service12 {

    public ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lockInterruptibly();
            System.out.println("lock begin " + Thread.currentThread().getName());
            for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
                String newString = new String();
                Math.random();
            }
            System.out.println("lock end " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

class Run12 {
    public static void main(String[] args) {
        Service12 service12 = new Service12();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service12.waitMethod();
            }
        };

        Thread threadA = new Thread(runnable);
        threadA.setName("A");
        threadA.start();

        Thread threadB = new Thread(runnable);
        threadB.setName("B");
        threadB.start();

        threadB.interrupt();

        System.out.println("main end ");
    }

}

//案例12
class Service11 {
    private ReentrantLock lock;

    public Service11(boolean isFair) {
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            System.out.println(lock.isHeldByCurrentThread());
            lock.lock();
            System.out.println(lock.isHeldByCurrentThread());
        } finally {
            lock.unlock();
        }
    }

    public void serviceAMethod() {
        try {
            System.out.println(lock.isLocked());
            lock.lock();
            System.out.println(lock.isLocked());
        } finally {
            lock.unlock();
        }
    }
}

class Run11 {
    public static void main(String[] args) {

        Service11 service11 = new Service11(true);

        new Thread(new Runnable() {
            @Override
            public void run() {
                service11.serviceMethod();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service11.serviceAMethod();
            }
        }).start();
    }
}

//案例11
class Service10 {

    public static ReentrantLock lock = new ReentrantLock();

    public static Condition newCondition = lock.newCondition();

    public void awaitMethod() {
        try {
            lock.lock();
            newCondition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyMethod() {
        try {
            lock.lock();
            System.out.println("有没有线程正在等待newCondition?" + lock.hasWaiters(newCondition) + " 线程数是多少？ " + lock.getWaitQueueLength(newCondition));
            newCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

class WaitRun {
    public static void main(String[] args) throws InterruptedException {
        Service10 service10 = new Service10();
        Runnable runnable = service10::awaitMethod;

        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnable);
        }

        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
        Thread.sleep(5000);

        service10.notifyMethod();

    }
}

//案例10
class Service9 {

    public static ReentrantLock reentrantLock = new ReentrantLock();

    public void awaitMethod() {
        try {
            reentrantLock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }
}

class Run01Demo {
    public static void main(String[] args) throws InterruptedException {

        Service9 service9 = new Service9();
        Runnable runnable = service9::awaitMethod;

        Thread threadA = new Thread(runnable);

        threadA.start();

        Thread.sleep(2000);

        Thread threadB = new Thread(runnable);

        threadB.start();

        System.out.println(Service9.reentrantLock.hasQueuedThread(threadA));

        System.out.println(Service9.reentrantLock.hasQueuedThread(threadB));

        System.out.println(Service9.reentrantLock.hasQueuedThreads());

    }
}


//案例9
class Service8 {

    public static ReentrantLock lock = new ReentrantLock();

    public static Condition conditionA = lock.newCondition();

    public void awaitMethod() {

        try {
            lock.lock();
            conditionA.await();
            System.out.println("持有conditionA 的线程对象继续执行了");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }

    public void signalMethod() {

        try {
            lock.lock();
            System.out.println("有" + lock.getWaitQueueLength(conditionA) + "个线程在等待newCondition");
            conditionA.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

class RunMain {
    public static void main(String[] args) throws InterruptedException {

        Service8 service8 = new Service8();
        Runnable runnableA = new Runnable() {
            @Override
            public void run() {
                service8.awaitMethod();
            }
        };
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnableA);
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
        Thread.sleep(2000);
        service8.signalMethod();
    }
}


//案例8
class Service7 {

    public static ReentrantLock lock = new ReentrantLock();

    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ServiceMethod1 getHoldCount=" + lock.getHoldCount());
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

class RunDemo {
    public static void main(String[] args) {

        Service7 service7 = new Service7();

        Runnable target = () -> {
            service7.serviceMethod();
        };

        Thread[] threads = new Thread[10];

        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(target);
        }

        try {
            for (int i = 0; i < 10; i++) {
                threads[i].start();
            }
            Thread.sleep(2000);

            System.out.println("有" + service7.lock.getQueueLength() + "个线程，在等待获取锁！");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//案例7
class Service6 {
    private ReentrantLock lock = new ReentrantLock();

    public void serviceMethod1() {
        try {
            lock.lock();
            System.out.println("ServiceMethod1 getHoldCount=" + lock.getHoldCount());
            serviceMethod2();
        } finally {
            lock.unlock();
        }
    }

    public void serviceMethod2() {
        try {
            lock.lock();
            System.out.println("ServiceMethod2 getHoldCount=" + lock.getHoldCount());
            serviceMethod3();
        } finally {
            lock.unlock();
        }
    }

    public void serviceMethod3() {
        try {
            lock.lock();
            System.out.println("ServiceMethod3 getHoldCount=" + lock.getHoldCount());
        } finally {
            lock.unlock();
        }
    }
}

class Run {
    public static void main(String[] args) {
        Service6 service6 = new Service6();
        service6.serviceMethod1();
    }
}


//案例6
class Service5 {
    private ReentrantLock reentrantLock;

    public Service5(boolean isFair) {
        reentrantLock = new ReentrantLock(isFair);
    }

    public void serviceMethod() {
        try {
            reentrantLock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName() + "获得锁定");
        } finally {
            reentrantLock.unlock();
        }
    }
}

class RunFair {
    public static void main(String[] args) {
        Service5 service5 = new Service5(false);

        Runnable runnable = () -> {
            System.out.println("★ 线程" + Thread.currentThread().getName() + "运行了");
            service5.serviceMethod();
        };
        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
    }
}

//案例5
class MyService4 {
    private static final ReentrantLock lock = new ReentrantLock();

    private static final Condition condition = lock.newCondition();

    private boolean hasValue = false;


    public void set() {
        try {
            lock.lock();
            while (hasValue) {
                condition.await();
            }
            System.out.println("打印☆");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void get() {
        try {
            lock.lock();
            while (!hasValue) {
                condition.await();
            }
            System.out.println("打印★");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

class Demo5 {

    public static void main(String[] args) {
        MyService4 myService4 = new MyService4();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    for (int i = 0; i < Integer.MAX_VALUE; i++) {
                        myService4.set();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    myService4.get();
                }
            }
        }).start();
    }
}


//案例4
class MyService3 {
    private static final Lock lock = new ReentrantLock();

    private static final Condition conditionA = lock.newCondition();

    private static final Condition conditionB = lock.newCondition();

    public void awaitA() {
        try {
            System.out.println(Thread.currentThread().getName() + "：进入等待");
            lock.lock();
            conditionA.await();
            System.out.println(Thread.currentThread().getName() + "：结束等待");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitB() {
        try {
            System.out.println(Thread.currentThread().getName() + "：进入等待");
            lock.lock();
            conditionB.await();
            System.out.println(Thread.currentThread().getName() + "：结束等待");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void sign_A() {
        try {
            lock.lock();
            conditionA.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void sign_B() {
        try {
            lock.lock();
            conditionB.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

class Demo4 {
    public static void main(String[] args) {
        MyService3 myService3 = new MyService3();
        new Thread(myService3::awaitA, "线程A").start();
        new Thread(myService3::awaitB, "线程B").start();
        try {
            Thread.sleep(3000);
            myService3.sign_A();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("==================");
        //myService3.sign_B();
    }
}


//案例3
class MyService2 {
    private static final Lock lock = new ReentrantLock();

    private static final Condition condition = lock.newCondition();

    public void awaitA() {
        try {
            System.out.println(Thread.currentThread().getName() + "：进入等待");
            lock.lock();
            condition.await();
            System.out.println(Thread.currentThread().getName() + "：结束等待");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitB() {
        try {
            System.out.println(Thread.currentThread().getName() + "：进入等待");
            lock.lock();
            condition.await();
            System.out.println(Thread.currentThread().getName() + "：结束等待");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signAll() {
        try {
            lock.lock();
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

class Demo3 {
    public static void main(String[] args) {
        MyService2 myService2 = new MyService2();
        new Thread(myService2::awaitA, "线程A").start();
        new Thread(myService2::awaitB, "线程B").start();
        try {
            Thread.sleep(3000);
            myService2.signAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//案例2
class MyService1 {
    private static final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out.println("A");
            condition.await();
            System.out.println("B");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("锁释放了");
        }
    }

    public void signalMethod() {
        try {
            lock.lock();
            condition.signal();
            try {
                Thread.sleep(5000);
                System.out.println("Thread Name = " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            lock.unlock();
        }
    }
}

//案例2
class Demo2 {
    public static void main(String[] args) {
        MyService1 myService1 = new MyService1();
        new Thread(myService1::waitMethod, "线程A").start();
        try {
            Thread.sleep(3000);
            myService1.signalMethod();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//案例1
class MyService {
    private static final Lock lock = new ReentrantLock();

    public void testMethod() {
        lock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println("ThreadName = " + Thread.currentThread().getName() + (i + 1));
        }
        lock.unlock();
    }
}

//案例1
class Demo1 {
    public static void main(String[] args) {

        MyService myService = new MyService();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                myService.testMethod();
            }
        }, "线程A");


        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                myService.testMethod();
            }
        }, "线程B");

        threadA.start();
        threadB.start();
    }
}

public class ReentrantLockDemo {
}
